package com.example.blew.omp.system.aspect;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.example.blew.omp.system.model.form.TimeLogForm;
import com.example.blew.omp.system.service.TimeLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;

@Aspect
@Component
@Slf4j
public class ApiAspect {

    private static final ThreadLocal<Long> START_TIME = new ThreadLocal<>();

    @Resource
    private TimeLogService timeLogService;

    /**
     * 不需要记录的class或method,后续项目组可自行做配置表
     */
    private static final String[] SKIP_CONTROLLERS = {"java.lang.Integer"};


    @Pointcut("execution(* com.example.blew.omp.system.controller.*.*(..))")
    public void apiMethodPointcut() {
    }


    @Before("apiMethodPointcut()")
    public void doBefore(JoinPoint point) {
        START_TIME.set(System.currentTimeMillis());
        //类名
        String className = point.getSignature().getDeclaringType().getSimpleName();
        //方法名
        String methodName = point.getSignature().getName();
        log.info("类:" + className + ",方法:" + methodName + "开始");
    }

    @AfterReturning(pointcut = "apiMethodPointcut()")
    public void doAfterReturing(JoinPoint point) {
        //类名
        String className = point.getSignature().getDeclaringType().getSimpleName();
        //方法名
        String methodName = point.getSignature().getName();
        //参数
        Object[] args = point.getArgs();
        //是否需要把参数也存入
        boolean para = true;
        for (Object arg : args) {
            if (arg instanceof HttpServletResponse || arg instanceof MultipartFile || arg instanceof MultipartFile[]) {
                para = false;
                break;
            }
        }
        //耗时
        long costTime = System.currentTimeMillis() - START_TIME.get();
        //ThreadLocal字段应该至少调用一次remove方法
        START_TIME.remove();
        log.info("类:" + className + ",方法:" + methodName + ",耗费时间:" + costTime + "ms");
        //不用记录的类或方法,后续项目组可以自行去做配置表
        if (Arrays.stream(SKIP_CONTROLLERS).anyMatch(s -> s.equals(className) || s.equals(className + "#" + methodName))) {
            return;
        }
        //只记录超过500毫秒的请求,这个在系统配置里面设置
        timeLogService.save(TimeLogForm.builder().method(methodName).costTime(costTime).businessData(para ? JSON.toJSONString(args, SerializerFeature.IgnoreNonFieldGetter) : "").build());
    }

//    @AfterThrowing(pointcut = "apiMethodPointcut()", throwing = "ex")
//    public void AfterThrowing(JoinPoint point, Throwable ex) {
//        //类名
//        String className = point.getSignature().getDeclaringType().getSimpleName();
//        //方法名
//        String methodName = point.getSignature().getName();
//        //参数
//        Object[] args = point.getArgs();
//        //是否需要把参数也存入
//        boolean para = true;
//        for (Object arg : args) {
//            if (arg instanceof HttpServletResponse || arg instanceof MultipartFile || arg instanceof MultipartFile[]) {
//                para = false;
//                break;
//            }
//        }
//        //耗时
//        long costTime = System.currentTimeMillis() - START_TIME.get();
//        //ThreadLocal字段应该至少调用一次remove方法
//        START_TIME.remove();
//        timeLogService.save(TimeLogForm.builder().method(methodName).costTime(costTime).businessData(para ? JSON.toJSONString(args, SerializerFeature.IgnoreNonFieldGetter) : "").build());
//        log.info("类:" + className + ",方法:" + methodName + ",耗费时间:" + costTime + "ms");
//    }
}
